package com.planw.beetl.utils;

import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.ui.JBColor;
import com.intellij.util.PlatformIcons;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;

public class ConstUtil {

  private static final Logger logger = Logger.getInstance(ConstUtil.class);

  private static volatile boolean isReady = false;

  private static Map<Project, BeetlSqlConst> beetlSqlConstCache = new HashMap<>();

  public static final Map<String, LookupElement> DEFAULT_FUNC_CACHE = new HashMap<>();

  public static final Map<String, LookupElement> EXT_FUNC_CACHE = new HashMap<>();

  public static boolean isReady() {

    return isReady;
  }

  public static void changeReadyState() {

    synchronized (ConstUtil.class) {
      logger.info("项目准备好");
      ConstUtil.isReady = true;
    }
  }

  public static BeetlSqlConst getBeetlSqlConst(PsiFile psiFile) {

    return getBeetlSqlConst(psiFile.getProject());
  }

  public static BeetlSqlConst getBeetlSqlConst(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .orElseGet(() -> new BeetSql3Const(project));
  }

  public static String getBaseMapperClassName(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .map(x -> x.BASE_MAPPER_BEETL_CLASS)
        .orElseGet(() -> new BeetSql3Const(project).BASE_MAPPER_BEETL_CLASS);
  }

  public static String getPageRequestClassName(PsiFile psiFile) {

    return getPageRequestClassName(psiFile.getProject());
  }

  public static String getPageRequestClassName(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .map(x -> x.PAGE_REQUEST_BEETL_CLASS)
        .orElseGet(() -> new BeetSql3Const(project).PAGE_REQUEST_BEETL_CLASS);
  }

  public static String getPageQueryClassName(PsiFile psiFile) {

    return getPageQueryClassName(psiFile.getProject());
  }

  public static String getPageQueryClassName(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .map(x -> x.PAGE_QUERY_BEETL_CLASS)
        .orElseGet(() -> new BeetSql3Const(project).PAGE_QUERY_BEETL_CLASS);
  }

  public static String getParamAnnotationClassName(PsiFile psiFile) {

    return getParamAnnotationClassName(psiFile.getProject());
  }

  public static String getParamAnnotationClassName(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .map(x -> x.PARAM_BEETL_CLASS)
        .orElseGet(() -> new BeetSql3Const(project).PARAM_BEETL_CLASS);
  }

  public static String getRootAnnotationClassName(PsiFile psiFile) {

    return getRootAnnotationClassName(psiFile.getProject());
  }

  public static String getRootAnnotationClassName(Project project) {

    return Optional.ofNullable(project).map(x -> beetlSqlConstCache.get(project))
        .map(x -> x.ROOT_BEETL_CLASS).orElseGet(() -> new BeetSql3Const(project).ROOT_BEETL_CLASS);
  }

  public static void initBeetlSql(Project project) {

    int beetlSqlVersion = MavenUtil.getBeetlSqlVersion(project);
    if (beetlSqlVersion == 2) {
      BeetlSqlConst beetlSqlConst = new BeetlSqlConst(project);
      beetlSqlConstCache.put(project, beetlSqlConst);
      if (DEFAULT_FUNC_CACHE.isEmpty()) {
        DEFAULT_FUNC_CACHE.putAll(loadBeetlSqlFunction(beetlSqlConst.defaultPropertiesFile));
      }
      if (EXT_FUNC_CACHE.isEmpty()) {
        EXT_FUNC_CACHE.putAll(loadBeetlSqlFunction(beetlSqlConst.extPropertiesFile));
      }
    } else if (beetlSqlVersion == 3) {
      BeetSql3Const beetSql3Const = new BeetSql3Const(project);
      beetlSqlConstCache.put(project, beetSql3Const);
      if (DEFAULT_FUNC_CACHE.isEmpty()) {
        DEFAULT_FUNC_CACHE.putAll(loadBeetlSqlFunction(beetSql3Const.defaultPropertiesFile));
      }
      if (EXT_FUNC_CACHE.isEmpty()) {
        EXT_FUNC_CACHE.putAll(loadBeetlSqlFunction(beetSql3Const.extPropertiesFile));
      }
    }
  }

  /**
   * 载入btsql.properties中的函数
   */
  private static Map<String, LookupElement> loadBeetlSqlFunction(VirtualFile propertiesFile) {

    Map<String, LookupElement> funcNameMap = new HashMap<>();
    if (propertiesFile == null) {
      return funcNameMap;
    }
    try (InputStream inputStream = propertiesFile.getInputStream();) {
      Properties properties = new Properties();
      properties.load(inputStream);
      Set<Object> keySet = properties.keySet();
      for (Object key : keySet) {
        String keyStr = String.valueOf(key);
        if (keyStr.startsWith("FN") || keyStr.startsWith("TAG")) {
          String name = keyStr.substring(keyStr.indexOf(".") + 1);
          LookupElement lookupElement = createFunctionLookupElement(name,
              properties.getProperty(keyStr));
          funcNameMap.put(name, lookupElement);
        }
      }
    } catch (IOException e) {
      logger.error("无法获取" + propertiesFile.getName() + "文件");
    }
    return funcNameMap;
  }

  private static LookupElement createFunctionLookupElement(String lookupStr, String typeText) {

    return LookupElementBuilder.create(lookupStr + "()").withCaseSensitivity(true)
        .withPresentableText(lookupStr).withIcon(PlatformIcons.FUNCTION_ICON)
        .withItemTextForeground(JBColor.BLACK).bold()
        .withTypeText(typeText, PlatformIcons.CLASS_ICON, true).withTypeIconRightAligned(true)
        .withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE);
  }

}
